home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / standards / sgml / nist / parse3 / diutil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-13  |  63.1 KB  |  1,903 lines

  1. /* National Institute of Standards and Technology (NIST)
  2. /* National Computer System Laboratory (NCSL)
  3. /* Office Systems Engineering (OSE) Group
  4. /* ********************************************************************
  5. /*                            D I S C L A I M E R
  6. /*                              (March 8, 1989)
  7. /*  
  8. /* There is no warranty for the NIST NCSL OSE SGML parser and/or the NIST
  9. /* NCSL OSE SGML parser validation suite.  If the SGML parser and/or
  10. /* validation suite is modified by someone else and passed on, NIST wants
  11. /* the parser's recipients to know that what they have is not what NIST
  12. /* distributed, so that any problems introduced by others will not
  13. /* reflect on our reputation.
  14. /* 
  15. /* Policies
  16. /* 
  17. /* 1. Anyone may copy and distribute verbatim copies of the SGML source
  18. /* code as received in any medium.
  19. /* 
  20. /* 2. Anyone may modify your copy or copies of SGML parser source code or
  21. /* any portion of it, and copy and distribute such modifications provided
  22. /* that all modifications are clearly associated with the entity that
  23. /* performs the modifications.
  24. /* 
  25. /* NO WARRANTY
  26. /* ===========
  27. /* 
  28. /* NIST PROVIDES ABSOLUTELY NO WARRANTY.  THE SGML PARSER AND VALIDATION
  29. /* SUITE ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
  30. /* EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  31. /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  32. /* THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
  33. /* WITH YOU.  SHOULD THE SGML PARSER OR VALIDATION SUITE PROVE DEFECTIVE,
  34. /* YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  35. /* 
  36. /* IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL NIST BE LIABLE FOR
  37. /* DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
  38. /* INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
  39. /* INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
  40. /* BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
  41. /* FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
  42. /* NIST) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF
  43. /* SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  44. */
  45.  
  46. /************************************************************************/
  47. /*   TITLE:          SGML PARSER                                        */
  48. /*   SYSTEM:         DOCUMENT PROCESSOR                                 */
  49. /*   SUBSYSTEM:                                                         */
  50. /*   SOURCE FILE:    DIUTIL.C                                           */
  51. /*   AUTHOR:         Steven Lindeman, Fred Maples                       */
  52. /*                                                                      */
  53. /*   DATE CREATED:                                                      */
  54. /*   LAST MODIFIED:                                                     */
  55. /*                                                                      */
  56. /*                  REVISIONS                                           */
  57. /*   WHEN      WHO            WHY                                       */
  58. /************************************************************************/
  59. #include <stdio.h>
  60. #include <ctype.h>
  61. #include "didefs.h"
  62. #include "diglobal.h"
  63.  
  64. /*----------------------------------------------*/
  65. /*      A D A L L O C                 */
  66. /* Allocates enough memory for one  attri-   */
  67. /* bute description linked list entry. */
  68. /*----------------------------------------------*/
  69. ATTRDESC *adalloc()
  70. {
  71.    /*   char *calloc();*/
  72.    ATTRDESC *retptr;
  73.    if ((retptr=(ATTRPTR) malloc(sizeof(ATTRDESC))) == NULL)
  74.       ourexit(2,"\nInsufficient memory in parse3.\n");
  75.    return(retptr);
  76. }
  77.  
  78. /*----------------------------------------------*/
  79. /*               O Q A L L O C                  */
  80. /*----------------------------------------------*/
  81. OUT_QUEUE *oqalloc()
  82. {
  83.    /*   char *calloc();*/
  84.    OUT_QUEUE *retptr;
  85.    if ((retptr=(OUT_QUEUE_PTR) malloc(sizeof(OUT_QUEUE))) == NULL)
  86.       ourexit(2,"\nInsufficient memory in parse3.\n");
  87.    return(retptr);
  88. }
  89.  
  90. /*------------------------------------------------------*/
  91. /*                 C H E C K _ C R                      */
  92. /* This routine dumps out the carriage returns  */
  93. /* that were previously saved.  At this point we   */
  94. /* know they are significant.       */
  95. /*------------------------------------------------------*/
  96. void check_cr(num_cr,cr_found,first_time,end_of_elt)
  97. unsigned *num_cr;
  98. BOOLEAN cr_found,*first_time,end_of_elt;
  99.    if (*first_time) {
  100.       (*put_ctr)('\n',ctrfp);
  101.       *first_time = FALSE;
  102.    }
  103.    if (cr_found) {
  104.       (*print_ctr)(ctrfp,"|");
  105.       while((*num_cr)-->0)
  106.          (*print_ctr)(ctrfp,"\n[]");
  107.       if (!end_of_elt)
  108.          (*put_ctr)('\n',ctrfp);
  109.    }
  110.    return;
  111. }
  112.  
  113. /*--------------------------------------------------------------*/
  114. /*                     C H E C K _ E N T I T Y                 */
  115. /* This routine is called when a general entity reference   */
  116. /* has occurred either in the data stream or from an  */
  117. /* attribute value literal.            */
  118. /*--------------------------------------------------------------*/
  119. void check_entity(cdata_attr,num_csdata,entptr,datatext_read,entname,actual_length,inside_attr,inchar)
  120. BOOLEAN cdata_attr;
  121. unsigned *num_csdata;
  122. ENTITYDESC *entptr;
  123. BOOLEAN *datatext_read;
  124. char entname[];
  125. int *actual_length;
  126. BOOLEAN inside_attr;
  127. int *inchar;
  128. {
  129.    char str_to_unget[LITLEN+6];
  130.  
  131.    entstack[entitylevel] = lookstack();
  132.    if (++entitylevel > ENTLVL)
  133.       ourexit(2,"\nError: Nesting level of entities > ENTLVL\n");
  134.    switch(entptr->entitytype) {
  135.    case KW_MS:
  136.       sprintf(str_to_unget,"<![%s]]>",entptr->entityvalue);
  137.       break;
  138.    case KW_STARTTAG:
  139.       sprintf(str_to_unget,"<%s>",entptr->entityvalue);
  140.       break;
  141.    case KW_ENDTAG:
  142.       sprintf(str_to_unget,"</%s>",entptr->entityvalue);
  143.       break;
  144.    case KW_MD:
  145.       sprintf(str_to_unget,"<!%s>",entptr->entityvalue);
  146.       break;
  147.    case KW_PI:
  148.       if (inside_attr)
  149.          ourexit(2,"\nError: Processing instruction invalid in attribute value literal.\n");
  150.       else {
  151.          (*print_ctr)(ctrfp,"\n[?%s]",entptr->entityvalue);
  152.          (*applic)(PROC_INST,entptr->entityvalue);
  153.       }
  154.       break;
  155.    case KW_CDATA: 
  156.    case KW_SDATA:
  157.       if (inside_attr && !cdata_attr)
  158.          ourexit(2,"\nError: CDATA or SDATA entity invalid in this attribute literal.\n");
  159.       strcpy(str_to_unget,entptr->entityvalue); 
  160.       *datatext_read = TRUE;
  161.       if (inside_attr)
  162.          *num_csdata += 1;  /* count of CDATA or SDATA references */
  163.       break;
  164.    case KW_SYSTEM: 
  165.    case KW_PUBLIC:
  166.       (*print_ctr)(ctrfp,"\n[&%s]",entname);
  167.       /*    if ((fpstack[++fpindx]=fopen("fred","rb")) == NULL)
  168.                ourexit(2,"Error: Unknown system entity reference.\n");
  169.       */
  170.       break;
  171.    default:
  172.       strcpy(str_to_unget,entptr->entityvalue); 
  173.       break;
  174.    }
  175.    if ((*inchar=our_fgetc(indoc)) != REFC)
  176.       if (*inchar == RE) { /* RS and RE are insignificant */
  177.          *inchar = our_fgetc(indoc);  /* get RS */
  178.          if (inside_attr)
  179.             *actual_length += 2;
  180.       }
  181.       else
  182.          our_ungetc(*inchar,indoc);
  183.    unget_entity(str_to_unget);
  184.    return;
  185. }
  186.  
  187. /*------------------------------------------------------*/
  188. /*               C H E C K _ F I X E D                  */
  189. /*     This routine guarantees that the attribute  */
  190. /*     declared as being FIXED matches the actual  */
  191. /*     value that was given.  If the two do not match */
  192. /*     exactly, an error condition is raised.      */
  193. /*------------------------------------------------------*/
  194. void check_fixed(defcode,str1,str2,length)
  195. ADFLT defcode;
  196. char str1[],str2[];
  197. int length;
  198. {
  199.    if (defcode==A_FIXED && strncmp(str1,str2,length)!=0) {
  200.       sprintf(error_msg,"%s'%s'.\n","\nError: FIXED attribute declared.  Must use ",str2);
  201.       FATAL_ERROR()
  202.    }
  203.    return;
  204. }
  205.  
  206. /*------------------------------------------------------*/
  207. /*       C R E A T E C M                      */
  208. /*                                                 */
  209. /*         Called by  :PUSHCREATE                     */
  210. /*                                                */
  211. /*         Returns    :pointer to the new             */
  212. /*                 content model                  */
  213. /*                                                */
  214. /*      Creates a copy of the given content model     */
  215. /*------------------------------------------------------*/
  216. TNODE *createcm(oldptr)
  217. TNODE *oldptr;
  218. {
  219.    TNODE *newptr,*newp,*oldp;
  220.  
  221.    if (oldptr != NULL) {
  222.       newptr = talloc();     /* allocate a node */
  223.       newptr->nodeid = oldptr->nodeid;    /* copy nodeid to new node */
  224.       newptr->occurind = newptr->copyoi = oldptr->occurind;
  225.       newptr->contreq = newptr->copycontreq = oldptr->contreq;
  226.       newptr->contref_attr = oldptr->contref_attr;
  227.  
  228.       /* ANDs are treated seperately, must build circular linked list
  229.                      instead of a binary tree.  each element in list is an element
  230.                      of the AND group */
  231.       if (oldptr->nodeid == AND) {
  232.          newp = newptr->u.llptr = createcm(oldptr->u.llptr);
  233.          oldp = oldptr->u.llptr;
  234.          while(oldp->next != oldptr->u.llptr) {
  235.             newp->next = createcm(oldp->next);  
  236.             oldp = oldp->next;
  237.             newp = newp->next;  /* move across both lists */
  238.          }
  239.          newp->next = newptr->u.llptr;   /* finish off circular list */
  240.       }
  241.       else {
  242.          newptr->left = createcm(oldptr->left);   /* create new left pointer */
  243.          newptr->u.right = createcm(oldptr->u.right); /* create new right ptr */
  244.       }
  245.       return(newptr);
  246.    }
  247.    return(NULL);
  248. }
  249.  
  250. /*------------------------------------------------------*/
  251. /*         C O M P A R E                  */
  252. /*                   */
  253. /*       Called by  :QSORT, BSEARCH                */
  254. /*                   */
  255. /*       Returns    :TRUE, FALSE                   */
  256. /*                   */
  257. /*       String compare to determine if two        */
  258. /*         strings are equal.                      */
  259. /*------------------------------------------------------*/
  260. compare(arg1,arg2)
  261. STENTRY *arg1,*arg2;
  262. {
  263.    return(strcmp((char *)arg1,(char *)arg2));
  264. }
  265.  
  266. /*------------------------------------------------------*/
  267. /*           D E C R O I                      */
  268. /*      This routine decrements the occurence indic-  */
  269. /* ators.  All that means is that an occurrence    */
  270. /* of this model token has occurred.      */
  271. /*------------------------------------------------------*/
  272. void decroi(ptr)
  273. TNODE *ptr;
  274. {
  275.    switch(ptr->occurind) {
  276.    case '+':          /* one or more   goes to  zero or more  */
  277.    case '*':          /* zero or more  goes to  zero or more  */
  278.       ptr->occurind = '*';
  279.       break;
  280. #ifdef NEW
  281.    case '*':          /* zero or more  goes to  zero or more  */
  282. #endif
  283.    case '?':          /* zero or one  goes to  none  */
  284.    case '1':          /* one          goes to  none  */
  285.       ptr->occurind = '#';
  286.       break;
  287.    default:
  288.       software_fault();
  289.    }
  290.    switch(ptr->contreq) {
  291.    case C_FTOTSO:
  292.       ptr->contreq = ptr->copycontreq = C_SOMETIMESO;
  293.       break;
  294.    case C_FTOWR:
  295.    case C_FTO:
  296.       ptr->contreq = C_NEVERO;
  297.       break;
  298.    case C_SOMETIMESO:
  299.    case C_NEVERO:
  300.    case C_ALWAYSO:
  301.       break;
  302.    default:
  303.       software_fault();
  304.    }
  305.    return;
  306. }
  307.  
  308. /*------------------------------------------------------*/
  309. /*               D E L E T E _ F I L E S                */
  310. /* Deletes temporary files built by DTD processor. */
  311. /* This routine is called only if the '-F' command */
  312. /* line option is left off.         */
  313. /*------------------------------------------------------*/
  314. void delete_files(path)
  315. char path[];
  316. {
  317.    char filename[PATHLEN];
  318.  
  319.    sprintf(filename,"%s%s",path,"dtdfile.sgm");
  320.    unlink(filename);
  321.    sprintf(filename,"%s%s",path,"attrfile.sgm");
  322.    unlink(filename);
  323.    sprintf(filename,"%s%s",path,"greffile.sgm");
  324.    unlink(filename);
  325.    sprintf(filename,"%s%s",path,"preffile.sgm");
  326.    unlink(filename);
  327.    sprintf(filename,"%s%s",path,"except.sgm");
  328.    unlink(filename);
  329.    return;
  330. }
  331.  
  332. /*----------------------------------------------*/
  333. /*         E X A L L O C                 */
  334. /* Allocates enough memory for one        */
  335. /* exception linked list entry.        */
  336. /*----------------------------------------------*/
  337. EXCEPTDESC *exalloc()
  338. {
  339.    /* char *calloc(); */
  340.    EXCEPTDESC *retptr;
  341.    if ((retptr=(EXCEPTPTR) malloc(sizeof(EXCEPTDESC))) == NULL)
  342.       ourexit(2,"\nInsufficient memory in parse3.\n");
  343.    return(retptr);
  344. }
  345.  
  346. /*------------------------------------------------------*/
  347. /*                 F L U S H _ B U F         */
  348. /*     This routine flushes the output buffer called  */
  349. /*     'outbuf' to the output document called 'outdoc'.  */
  350. /*     Outbuf is assumed to not be null terminated,   */
  351. /*     so a null is placed at the end of the buffer   */
  352. /*     pointed to by bufptr.           */
  353. /*------------------------------------------------------*/
  354. void flush_buf()
  355. {
  356.    if (bufptr != 0) {
  357.       outbuf[bufptr] = '\0';  /* bufptr always points to next entry place */
  358.       (*print_ctr)(ctrfp,"%s",outbuf);
  359.       bufptr = 0;  /* points to end of buffer, nothing in buffer now */
  360.    }
  361.    empty_queue();
  362.    return;
  363. }
  364.  
  365. /*----------------------------------------------*/
  366. /*      G E A L L O C                 */
  367. /* Allocates enough memory for one entity */
  368. /* description linked list entry.      */
  369. /*----------------------------------------------*/
  370. ENTITYDESC *gealloc()
  371. {
  372.    /* char *calloc(); */
  373.    ENTITYDESC *retptr;
  374.    if ((retptr=(ENTITYPTR) malloc(sizeof(ENTITYDESC))) == NULL)
  375.       ourexit(2,"\nInsufficient memory in parse3.\n");
  376.    return(retptr);
  377. }
  378.  
  379. /*----------------------------------------------*/
  380. /*      G R A L L O C                 */
  381. /* Allocates enough memory for one group  */
  382. /* description linked list entry.      */
  383. /*----------------------------------------------*/
  384. GROUPDESC *gralloc()
  385. {
  386.    /* char *calloc(); */
  387.    GROUPDESC *retptr;
  388.    if ((retptr=(GROUPPTR) malloc(sizeof(GROUPDESC))) == NULL)
  389.       ourexit(2,"\nInsufficient memory in parse3.\n");
  390.    return(retptr);
  391. }
  392.  
  393. /*----------------------------------------------*/
  394. /*    I D _ I D R E F _ A L L O C          */
  395. /* Allocates enough memory for one ID or  */
  396. /* IDREF description linked list entry.   */
  397. /*----------------------------------------------*/
  398. ID_IDREF_DESC *id_idref_alloc()
  399. {
  400.    /* char *calloc(); */
  401.    ID_IDREF_DESC *retptr;
  402.    if ((retptr=(ID_IDREF_PTR) malloc(sizeof(ID_IDREF_DESC))) == NULL)
  403.       ourexit(2,"\nInsufficient memory in parse3.\n");
  404.    return(retptr);
  405. }
  406.  
  407. /*------------------------------------------------------*/
  408. /*                     I N C R O I                      */
  409. /*        Increments the occurence indicators.     */
  410. /*------------------------------------------------------*/
  411. void incroi(ptr)
  412. TNODE *ptr;
  413. {
  414.    switch(ptr->occurind) {
  415.    case '*':
  416.       ptr->occurind = '+';  /* zero or more goes to one or more */
  417.       break;
  418.    case '?':
  419.       ptr->occurind = '1';  /* optional goes to required */
  420.       break;
  421.    default:
  422.       software_fault();
  423.    }
  424.    return;
  425. }
  426.  
  427. /*------------------------------------------------------*/
  428. /*                   I N P U T _ P S                    */
  429. /* This routine is used to input parameter      */
  430. /* seperators that can be found in the front */
  431. /* part of marked sections.  It gets as many */
  432. /* as possible and returns the number that it   */
  433. /* found.                  */
  434. /*------------------------------------------------------*/
  435. inputps(penthead)
  436. ENTITYDESC *penthead;
  437. {
  438.    int inchar;
  439.    unsigned sepcount = 0;
  440.  
  441.    for(;;) {
  442.       switch (inchar=our_fgetc(indoc)) {
  443.       case RS:
  444.       case RE:   
  445.       case SPACE:  
  446.          sepcount++;
  447.          break;
  448.       case OUR_EE:
  449.          sepcount++;
  450.          entitylevel--;
  451.          break;
  452.          /* must check if parameter entity reference */
  453.       case PERO:
  454.          if ((inchar = our_fgetc(indoc)) == EOF)
  455.             return(EOF);
  456.          /* if it is a parameter entity reference ...*/
  457.          if (isalpha(inchar)){
  458.             our_ungetc(inchar, indoc);
  459.             if (++entitylevel > ENTLVL)
  460.                ourexit(2,"\nError: Number of open entities > ENTLVL\n");
  461.             reslvpref(penthead);
  462.             sepcount++;
  463.             break;
  464.          }
  465.          else {
  466.             our_ungetc(inchar, indoc);
  467.             our_ungetc(PERO, indoc);
  468.             return(sepcount);
  469.          }
  470.       case '-':
  471.          if ((inchar = our_fgetc(indoc)) == EOF)
  472.             return(EOF);
  473.          if (inchar == '-') {
  474.             inpcomment();
  475.             sepcount++;
  476.             break;
  477.          }
  478.          our_ungetc(inchar, indoc);
  479.          our_ungetc('-', indoc);
  480.          return(sepcount);
  481.       default:
  482.          our_ungetc(inchar, indoc);
  483.          return(sepcount);
  484.       }
  485.    }
  486. }
  487.  
  488. /*------------------------------------------------------*/
  489. /*                I N P C O M M E N T                   */
  490. /* This routine inputs a comment from indoc. */
  491. /*------------------------------------------------------*/
  492. void inpcomment()
  493.    int inchar;
  494.    for(;;) {
  495.       if ((inchar=our_fgetc(indoc)) == EOF)
  496.          ourexit(2,"\nError: EOF found while processing comment");
  497.       if (inchar != '-') 
  498.          continue;
  499.       if ((inchar=our_fgetc(indoc)) == EOF)
  500.          ourexit(2,"\nError: EOF found while processing comment");
  501.       if (inchar == '-')
  502.          return;
  503.    }
  504.    return;
  505. }
  506.  
  507. /*------------------------------------------------------*/
  508. /*         I S A L L O C                  */
  509. /* This routine allocates enough memory for one */
  510. /* input stack entry.                        */
  511. /*------------------------------------------------------*/
  512. INPUT_STACK *isalloc()
  513. {
  514.    /* char *calloc(); */
  515.    INPUT_STACK *retptr;
  516.    if ((retptr=(INPUT_STACK_PTR) malloc(sizeof(INPUT_STACK))) == NULL)
  517.       ourexit(2,"\nInsufficient memory in parse3.\n");
  518.    return(retptr);
  519. }
  520.  
  521. /*------------------------------------------------------*/
  522. /*              L I N S R C H             */
  523. /*      This routine performs a search on the symbol    */
  524. /*      table for the address of the record correspond- */
  525. /*      ing to the token passed to it.  If there is   */
  526. /*      not an entry in the symbol table for that  */
  527. /*      token, a NULL ptr is returned.       */
  528. /*------------------------------------------------------*/
  529. STENTRY *linsrch(symtable,token,numsym)
  530. STENTRY symtable[];
  531. int token,numsym;
  532. {
  533.    int thissym;
  534.  
  535.    thissym = 0;
  536.    while(thissym!=numsym && symtable[thissym].tokenid!=token)
  537.       thissym++;
  538.    return(thissym < numsym ? &(symtable[thissym]) : NULL); 
  539. }
  540.  
  541. /*------------------------------------------------------*/
  542. /*                   O U R E X I T                      */
  543. /*                   */
  544. /*     Called by:     everybody           */
  545. /*                   */
  546. /*     Returns:       doesn't          */
  547. /*                   */
  548. /*     This routine prints an explanatory error    */
  549. /*     message and then terminates program execution.   */
  550. /*------------------------------------------------------*/
  551. void ourexit(errcode,msg)
  552. int errcode;
  553. char *msg;
  554. {
  555.    static int error_count=0;
  556.  
  557.    fprintf(stdout,"%s\n",msg);
  558.    switch(errcode) {
  559.    case 0:
  560.       break;
  561.    default:
  562.       exit(99);
  563.    }
  564.    if (error_count++ > MAX_ERRORS)
  565.       exit(99);
  566. }
  567.  
  568. /*------------------------------------------------------*/
  569. /*             P L A C E _ I N _ Q U E U E              */
  570. /*------------------------------------------------------*/
  571. void place_in_queue(thiscode,thisstr1,thisstr2)
  572. int thiscode;
  573. char *thisstr1,*thisstr2;
  574. {
  575.    OUT_QUEUE *ptr,*curr;
  576.  
  577.    ptr = oqalloc();
  578.    ptr->code = thiscode;
  579.    strcpy(ptr->str1,thisstr1);
  580.    strcpy(ptr->str2,thisstr2);
  581.    ptr->next = NULL;
  582.    if (head == NULL)
  583.       head = ptr;
  584.    else {
  585.       for (curr=head; curr->next!=NULL; curr=curr->next);
  586.       curr->next = ptr;
  587.    }
  588.    return;
  589. }
  590.  
  591. /*------------------------------------------------------*/
  592. /*                 E M P T Y _ Q U E U E                */
  593. /*------------------------------------------------------*/
  594. void empty_queue()
  595. {
  596.    OUT_QUEUE *curr,*temp;
  597.    for (curr=head; curr!=NULL; temp=curr, curr=curr->next, free((char *)temp)) {
  598.       switch(curr->code) {
  599.       case TAG_NAME:
  600.          (*applic)(TAG_NAME,curr->str1,"");
  601.          break;
  602.       case TAG_ATTR:
  603.          (*applic)(TAG_ATTR,curr->str1,curr->str2);
  604.          break;
  605.       case TAG_END:
  606.          (*applic)(TAG_END,"","");
  607.          break;
  608.       case DATA_STG:
  609.          (*applic)(DATA_STG,curr->str1,"");
  610.          break;
  611.       case PROC_INST:
  612.          (*applic)(PROC_INST,curr->str1,"");
  613.          break;
  614.       case END_TAG_NAME:
  615.          (*applic)(END_TAG_NAME,curr->str1,"");
  616.          break;
  617.       }
  618.    }
  619.    head = NULL;
  620.    return;
  621. }
  622.  
  623. /*------------------------------------------------------*/
  624. /*                C L E A R _ Q U E U E                 */
  625. /*------------------------------------------------------*/
  626. void clear_queue()
  627. {
  628.    OUT_QUEUE *curr,*temp;
  629.    for (curr=head; curr!=NULL; temp=curr, curr=curr->next, free((char *)temp));
  630.    head = NULL;
  631.    return;
  632. }
  633.  
  634. /*------------------------------------------------------*/
  635. /*       P U S H                          */
  636. /*                                                 */
  637. /*         Called by  :PUSHCREATE, LOOKSTACK       */
  638. /*                                                 */
  639. /*         Returns    :VOID                        */
  640. /*                                                 */
  641. /*         Pushes a symbol table entry             */
  642. /*           pointer onto a push-down stack.       */
  643. /*------------------------------------------------------*/
  644. void push(ptr)
  645. STENTRY *ptr;
  646. {
  647.    if (sp < TAGLVL)
  648.       stack[sp++]=ptr;    /* push ptr on stack */
  649.    else             /* stack exceeds TAGLVL (24) */
  650.       ourexit(2,"\nError: Number of open elements > TAGLVL.\n");
  651.    return;
  652. }
  653.  
  654. /*------------------------------------------------------*/
  655. /*       P O P             */
  656. /*          Called by  :POPFREE, LOOKSTACK              */
  657. /*          Returns    :pointer to symbol table entry   */
  658. /*                                                */
  659. /*          Pops a symbol table entry pointer         */
  660. /*        off of a push-down stack               */
  661. /*------------------------------------------------------*/
  662. STENTRY *pop()
  663. {
  664.    if (sp > 0)
  665.       return(stack[--sp]);    /* pop ptr off stack */
  666.    else
  667.       return(NULL);
  668. }
  669.  
  670. /*------------------------------------------------------*/
  671. /*         P O P F R E E                     */
  672. /*      This routine pops a ptr from content model ptr  */
  673. /* stack and deletes corresponding content model.  */
  674. /*------------------------------------------------------*/
  675. STENTRY *popfree(ptr)
  676. TNODE *ptr;
  677. {
  678.    STENTRY *retptr;
  679.    EXCEPTDESC *p;
  680.  
  681.    retptr = pop();
  682.    retptr->num_open--;
  683.  
  684.    if (currexcl!=NULL && retptr->miniexcept&EXCL_MASK && retptr->num_open==0) {
  685.       if (currexcl == retptr->exclusion)
  686.          currexcl = NULL;
  687.       else {
  688.          p = last_sublist(currexcl,retptr->exclusion);  /* P can't be NULL */
  689.          p->nextglobal = NULL;
  690.       }
  691.       retptr->miniexcept &= ~EXCL_MASK;  /* disallow exclusions */
  692.    }
  693.  
  694.    if (currincl!=NULL && retptr->miniexcept&INCL_MASK && retptr->num_open==0) {
  695.       if (currincl == retptr->inclusion)
  696.          currincl = NULL;
  697.       else {
  698.          p = last_sublist(currincl,retptr->inclusion); /* P can't be NULL */
  699.          p->nextglobal = NULL;
  700.       }
  701.       retptr->miniexcept &= ~INCL_MASK;  /* disallow inclusions */
  702.    }
  703.    delete(ptr);
  704.    return(retptr);
  705. }
  706.  
  707. /*------------------------------------------------------*/
  708. /*                 P U S H C R E A T E                */
  709. /*                   */
  710. /*      Returns:    ptr to new content model    */
  711. /*                   */
  712. /*      pushes ptr on stack and creates a          */
  713. /*      content model from the virgin copy         */
  714. /*------------------------------------------------------*/
  715. TNODE *pushcreate(tp)
  716. STENTRY *tp;
  717. {
  718.    EXCEPTDESC *p;
  719.  
  720.    tp->num_open++;   /* number of currently open elements for this one */
  721.  
  722.    if (!(tp->miniexcept & EXCL_MASK))
  723.       if ((p=last_global(currexcl)) == NULL)
  724.          currexcl = tp->exclusion;
  725.       else
  726.          p->nextglobal = tp->exclusion;
  727.    if (tp->exclusion != NULL)
  728.       tp->miniexcept |= EXCL_MASK;
  729.  
  730.    if (!(tp->miniexcept & INCL_MASK))
  731.       if ((p=last_global(currincl)) == NULL)
  732.          currincl = tp->inclusion;
  733.       else
  734.          p->nextglobal = tp->inclusion;
  735.    if (tp->inclusion != NULL)
  736.       tp->miniexcept |= INCL_MASK;
  737.  
  738.    if (find_except(currexcl,tp->tokenid) == TRUE) {
  739.       sprintf(error_msg,"\n%s%s%s\n","Error: Invalid tokenid, ",tp->nametoken," is excluded.");
  740.       FATAL_ERROR()
  741.    }
  742.    push(tp);
  743.    return(createcm(tp->cmptr));
  744. }
  745.  
  746. /*------------------------------------------------------*/
  747. /*            P U T C H A R _ O U T B U F               */
  748. /*        Puts a character into the output buffer.      */
  749. /*------------------------------------------------------*/
  750. void putchar_outbuf(inchar)
  751. int inchar;
  752. {
  753.    outbuf[bufptr++] = inchar;
  754.    if (bufptr >= TAGLEN+200)
  755.       flush_buf();
  756.    return;
  757. }
  758.  
  759. /*------------------------------------------------------*/
  760. /*              P U T S T R _ O U T B U F               */
  761. /*     Puts a character string into the output buffer   */
  762. /*------------------------------------------------------*/
  763. void putstr_outbuf(string)
  764. char string[];
  765. {
  766.    if (bufptr+strlen(string) >= TAGLEN+200)
  767.       flush_buf();
  768.    if (strlen(string) >= TAGLEN+200)
  769.       (*print_ctr)(ctrfp,"%s",string);
  770.    outbuf[bufptr] = '\0';
  771.    strcat(outbuf,string);
  772.    bufptr += strlen(string); /* don't need the null string yet */
  773.    return;
  774. }
  775.  
  776. /*------------------------------------------------------*/
  777. /*                   R E D U C E O I                    */
  778. /*      This routine reduces the occurence indicators.  */
  779. /* This is done in the initilization part to make  */
  780. /* sub-models optional if their parent nodes are   */
  781. /* optional.               */
  782. /*------------------------------------------------------*/
  783. void reduceoi(ptr)
  784. TNODE *ptr;
  785. {
  786.    switch(ptr->occurind) {
  787.    case '+':
  788.       ptr->copyoi = ptr->occurind = '*';
  789.       break;
  790.    case '1':
  791.       ptr->copyoi = ptr->occurind = '?';
  792.       break;
  793.    default:
  794.       software_fault();
  795.    }
  796.    return;
  797. }
  798.  
  799. /*------------------------------------------------------*/
  800. /*                 R E S T O R E O I                    */
  801. /*     This routine restores the occurance indicators   */
  802. /*     of the whole tree to their original values       */
  803. /*------------------------------------------------------*/
  804. void restoreoi(ptr)
  805. TNODE *ptr;
  806. {
  807.    TNODE *currp;
  808.  
  809.    if (ptr != NULL) {
  810.       if (ptr->nodeid == AND) {
  811.          currp = ptr->u.llptr;
  812.          while(currp->next != ptr->u.llptr) {  /* restore each one in list */
  813.             restoreoi(currp);
  814.             currp = currp->next;
  815.          }
  816.          restoreoi(currp);  /* don't forget to restore last one  */
  817.       }
  818.       else {
  819.          restoreoi(ptr->left);    /* restore left subtree */
  820.          restoreoi(ptr->u.right); /* restore right subtree */
  821.       }
  822.       ptr->occurind = ptr->copyoi;  /* restores oi from unused copy */
  823.       switch(ptr->contreq) {
  824.       case C_NEVERO:
  825.          if (ptr->copycontreq != C_FTO)
  826.             ptr->contreq = ptr->copycontreq;
  827.          break;
  828.       case C_SOMETIMESO:
  829.          if (ptr->copycontreq != C_FTOTSO)
  830.             ptr->contreq = ptr->copycontreq;
  831.          break;
  832.       default:
  833.          ptr->contreq = ptr->copycontreq;
  834.          break;
  835.       }
  836.    }
  837.    return;
  838. }
  839.  
  840. /*------------------------------------------------------*/
  841. /*    R E Q _ N O T _ P R O C       */
  842. /* Traverses through the attribute list to decide  */
  843. /* if any attributes were REQUIRED but not pro- *
  844. /* cessed.  FALSE is returned if none were found   */
  845. /* and TRUE is returned if at least one was found. */
  846. /*------------------------------------------------------*/
  847. req_not_proc(thisadp)
  848. ATTRDESC *thisadp;
  849. {
  850.    BOOLEAN retval;
  851.    retval = FALSE;
  852.    while(retval==FALSE && thisadp!=NULL)
  853.       if ((thisadp->processed==FALSE) && ((thisadp->defcode==A_REQD) ||
  854.           (thisadp->defcode==A_CURRENT && thisadp->u2.currgrp==NULL)))
  855.          retval = TRUE;
  856.       else
  857.          thisadp = thisadp->next;
  858.    return(retval);
  859. }
  860.  
  861. /*------------------------------------------------------*/
  862. /*        R E S L V P R E F         */
  863. /* This routine resolves any parameter entity refer-    */
  864. /* ences at a separator level. It inputs the entity     */
  865. /* name, searches a table on the name getting its  */
  866. /* entity text, and 'ungets' the text for further  */
  867. /* processing.                                        */
  868. /*------------------------------------------------------*/
  869. void reslvpref(penthead)
  870. ENTITYDESC *penthead;
  871. {
  872.    char namearray[NAMELEN+1];
  873.    char tarray[LITLEN+6];
  874.    int inchar;
  875.    ENTITYDESC *entptr;
  876.  
  877.    /* input the parameter entity name */
  878.    if (get_entname(namearray,nullfnc) < NAMELEN-1) {
  879.  
  880.       if ((entptr=find_entity(penthead,namearray,FALSE)) == NULL) {
  881.          sprintf(error_msg,"\n%s'%s'.\n","Error: Unknown parameter entity reference ",namearray);
  882.          FATAL_ERROR()
  883.       }
  884.       switch(entptr->entitytype){
  885.       case KW_MD:
  886.          sprintf(tarray,"%s%s%s","<!",entptr->entityvalue,">");
  887.          if ((inchar=our_fgetc(indoc)) != EOF)
  888.             ourexit(2,"\nError: EOF found while resolving parameter entity reference.\n");
  889.          if (inchar != REFC)
  890.             if (inchar == RE)   /* RS and RE are insignificant */
  891.                inchar = our_fgetc(indoc);  /* get RS */
  892.             else
  893.                our_ungetc(inchar, indoc);
  894.          unget_entity(tarray);
  895.          break;
  896.       case KW_ENDTAG:
  897.          sprintf(tarray,"%s%s%s","</",entptr->entityvalue,">");
  898.          if ((inchar=our_fgetc(indoc)) != EOF)
  899.             ourexit(2,"\nError: EOF found while resolving parameter entity reference.\n");
  900.          if (inchar != REFC)
  901.             if (inchar == RE)   /* RS and RE are insignificant */
  902.                inchar = our_fgetc(indoc);  /* get RS */
  903.             else
  904.                our_ungetc(inchar, indoc);
  905.          unget_entity(tarray);
  906.          break;
  907.       case KW_STARTTAG:
  908.          sprintf(tarray,"%s%s%s","<",entptr->entityvalue,">");
  909.          if ((inchar=our_fgetc(indoc)) != EOF)
  910.             ourexit(2,"\nError: EOF found while resolving parameter entity reference.\n");
  911.          if (inchar != REFC)
  912.             if (inchar == RE)   /* RS and RE are insignificant */
  913.                inchar = our_fgetc(indoc);  /* get RS */
  914.             else
  915.                our_ungetc(inchar, indoc);
  916.          unget_entity(tarray);
  917.          break;
  918.       case KW_MS:
  919.          sprintf(tarray,"%s%s%s","<![",entptr->entityvalue,"]]>");
  920.          if ((inchar=our_fgetc(indoc)) == EOF)
  921.             ourexit(2,"\nError: EOF found while resolving parameter entity reference.\n");
  922.          if (inchar != REFC)
  923.             if (inchar == RE)   /* RS and RE are insignificant */
  924.                inchar = our_fgetc(indoc);  /* get RS */
  925.             else
  926.                our_ungetc(inchar, indoc);
  927.          unget_entity(tarray);
  928.          break;
  929.       case NULL:
  930.          if ((inchar=our_fgetc(indoc)) == EOF)
  931.             ourexit(2,"\nError: EOF found while resolving parameter entity reference");
  932.          if (inchar != REFC)
  933.             if (inchar == RE)   /* RS and RE are insignificant */
  934.                inchar = our_fgetc(indoc);  /* get RS */
  935.             else
  936.                our_ungetc(inchar, indoc);
  937.          /* unget parameter literal */
  938.          unget_entity(entptr->entityvalue);
  939.          break;
  940.          /* any other syntactic literal is illegal */
  941.       default:
  942.          ourexit(2,"\nError: Illegal use of syntactic literal in a PS entity reference.\n");
  943.          break;
  944.       }
  945.    }
  946.    else
  947.       ourexit(2,"\nError: Reference name not found in PS entity reference.\n");
  948.    return;
  949. }
  950.  
  951. /*------------------------------------------------------*/
  952. /*                  S A V E _ C R S                     */
  953. /* During the processing of data, carriage returns */
  954. /* are read and saved.  They may be output later   */
  955. /* if it is found that are significant.      */
  956. /*------------------------------------------------------*/
  957. BOOLEAN save_crs(num_cr,inchar)
  958. unsigned *num_cr;
  959. int *inchar;
  960. {
  961.    BOOLEAN cr_found;
  962.    for (cr_found = FALSE; *inchar == RE; (*num_cr)++) {
  963.       cr_found = TRUE;
  964.       if ((*inchar=our_fgetc(indoc)) == RS)  /* should be a RS */
  965.          *inchar = our_fgetc(indoc);
  966.    }
  967.    return(cr_found);
  968. }
  969.  
  970. /*------------------------------------------------------*/
  971. /*    S O F T W A R E _ F A U L T      */
  972. /* This routine should NEVER be called.  If it  */
  973. /* is called, the parser has taken an unpredicted  */
  974. /* path of execution and the program is halted. */
  975. /*------------------------------------------------------*/
  976. void software_fault()
  977. {
  978.    fprintf(stderr,"Internal parser error.  Contact Jim Heath of NBS @ (301) 975-3350.\n");
  979.    exit(99);
  980. }
  981.  
  982. /*----------------------------------------------*/
  983. /*      T A L L O C                   */
  984. /*                                              */
  985. /*     Called by   :BUILDTREE                   */
  986. /*                                              */
  987. /*     Returns     :ptr to allocated node       */
  988. /*                                              */
  989. /*     Allocates memory for one tree node.      */
  990. /*----------------------------------------------*/
  991. TNODE *talloc()
  992. {
  993.    /* char *calloc(); */
  994.    TNODE *retptr;
  995.    if ((retptr=(TPTR) malloc(sizeof(TNODE))) == NULL)
  996.       ourexit(2,"\nInsufficient memory in parse3.\n");
  997.    return(retptr);
  998. }
  999.  
  1000. /*------------------------------------------------------*/
  1001. /*                    T E S T O I                       */
  1002. /*     This routine tests to see if occurance indicator */
  1003. /*     is mandatory or optional.                   */
  1004. /*------------------------------------------------------*/
  1005. OCCURIND testoi(ptr)
  1006. TNODE *ptr;
  1007. {
  1008.    OCCURIND retval;
  1009.  
  1010.    switch(ptr->occurind) {
  1011.    case '1':         /* occurind is one */
  1012.       retval = ONE;
  1013.       break;
  1014.    case '+':         /* occurind is one or more */
  1015.       retval = PLUS;
  1016.       break;
  1017.    case '?':         /* occurind is zero or one */
  1018.    case '*':         /* occurind is zero or more */
  1019.       retval = OPT;
  1020.       break;
  1021.    case '#':         /* occurind is none */
  1022.       retval = OI_IS_NULL;
  1023.       break;
  1024.    default:
  1025.       software_fault();
  1026.    }
  1027.    return(retval);
  1028. }
  1029.  
  1030. /*------------------------------------------------------*/
  1031. /*                U N G E T _ E N T I T Y               */
  1032. /* This routine simply 'ungets' the given entity   */
  1033. /* string onto the input stack.  First the SGML */
  1034. /* 'Ee' (Entity end) signal is pushed on the */
  1035. /* stack, then the string is pushed in reverse  */
  1036. /* order by unget_string.           */
  1037. /*------------------------------------------------------*/
  1038. void unget_entity(string)
  1039. char string[];
  1040. {
  1041.    our_ungetc(OUR_EE,indoc);
  1042.    unget_string(string);
  1043.    return;
  1044. }
  1045.  
  1046. /*------------------------------------------------------*/
  1047. /*                U N G E T _ S T R I N G               */
  1048. /* This routine simply 'ungets' the given string   */
  1049. /* onto the input stack.   Remember that the    */
  1050. /*      string must be processed in reverse order. */
  1051. /*------------------------------------------------------*/
  1052. void unget_string(string)
  1053. char string[];
  1054. {
  1055.    register int i;
  1056.    for (i=strlen(string)-1; i>=0; i--)
  1057.       our_ungetc(string[i],indoc);
  1058.    return;
  1059. }
  1060.  
  1061. /*------------------------------------------------------*/
  1062. /*          U N G E T T O K E N                  */
  1063. /*  Places the given token (tag) back onto the     */
  1064. /*       input stream.                        */
  1065. /*------------------------------------------------------*/
  1066. void ungettoken(token,tp)
  1067. int token;
  1068. STENTRY *tp;
  1069. {
  1070.    state = GETOLD;     /* set state to read from input stream */
  1071.    holdtoken = token;
  1072.    holdtp = tp;        /* get table location from hold area */
  1073.    return;
  1074. }
  1075.  
  1076. /*------------------------------------------------------*/
  1077. /*         U N P R O C E S S        */
  1078. /* Traverses through the attribute list and  */
  1079. /* turns off the flag describing whether this   */
  1080. /* name has been processed in this tag.      */
  1081. /*------------------------------------------------------*/
  1082. void unprocess(thisadp)
  1083. ATTRDESC *thisadp;
  1084. {
  1085.    while(thisadp != NULL) {
  1086.       thisadp->processed = FALSE;
  1087.       thisadp = thisadp->next;
  1088.    }
  1089.    return;
  1090. }
  1091.  
  1092. /*--------------------------------------------------------------*/
  1093. /*                 C H E C K _ F O R _ M D O                   */
  1094. /* This routine is called when the "<!" has already   */
  1095. /* been read while processing PCDATA.        */
  1096. /*--------------------------------------------------------------*/
  1097. STATUS check_for_mdo(more_subdata,num_cr,cr_found,pcdata_ft)
  1098. BOOLEAN *more_subdata;
  1099. unsigned *num_cr;
  1100. BOOLEAN cr_found,*pcdata_ft;
  1101. {
  1102.    int inchar;
  1103.    STATUS retval;
  1104.  
  1105.    if ((inchar=our_fgetc(indoc)) == '-')
  1106.       if ((inchar=our_fgetc(indoc)) == '-') {
  1107.          unget_string("<!--");
  1108.          *more_subdata = FALSE;
  1109.       }
  1110.       else {
  1111.          retval = FOUND;
  1112.          check_cr(num_cr,cr_found,pcdata_ft,FALSE);
  1113.          (*print_ctr)(ctrfp,"<!-");
  1114.          (*applic)(DATA_STG,"<!-","");
  1115.          our_ungetc(inchar,indoc);
  1116.       }
  1117.    else
  1118.       if (isalpha(inchar) || inchar=='[' || inchar==MARKUP_END) {
  1119.          our_ungetc(inchar,indoc);
  1120.          unget_string("<!");   
  1121.          *more_subdata = FALSE;
  1122.       }
  1123.       else {
  1124.          retval = FOUND;
  1125.          check_cr(num_cr,cr_found,pcdata_ft,FALSE);
  1126.          (*print_ctr)(ctrfp,"<!");
  1127.          (*applic)(DATA_STG,"<!","");
  1128.          our_ungetc(inchar,indoc);
  1129.       }
  1130.    return(retval);
  1131. }
  1132.  
  1133. /*------------------------------------------------------*/
  1134. /*    C R O S S _ I D _ I D R E F      */
  1135. /* Performs a cross reference evaluation for IDs   */
  1136. /* and IDREFs to make sure there is an ID found */
  1137. /* for every IDREF.  There is no requirement that  */
  1138. /* states an IDREF must be found for every ID.  */
  1139. /*------------------------------------------------------*/
  1140. ID_IDREF_DESC *cross_id_idref(idptr,idrefptr)
  1141. ID_IDREF_DESC *idptr,*idrefptr;
  1142. {
  1143.    while(idrefptr!=NULL && find_id(idptr,idrefptr->name)==TRUE)
  1144.       idrefptr = idrefptr->next;
  1145.    return(idrefptr);
  1146. }
  1147.  
  1148. /*------------------------------------------------------*/
  1149. /*       D E L E T E                     */
  1150. /*                                               */
  1151. /*     Called by  :DELETE,POPFREE                  */
  1152. /*                                                 */
  1153. /*     Returns    :VOID                            */
  1154. /*                                               */
  1155. /*     Deletes the binary tree pointed to by ptr   */
  1156. /*------------------------------------------------------*/
  1157. void delete(ptr)
  1158. TNODE *ptr;
  1159. {
  1160.    TNODE *currp,*futp;
  1161.    if (ptr != NULL) {
  1162.       if (ptr->nodeid == AND) {
  1163.          currp = ptr->u.llptr;
  1164.          while(currp->next != ptr->u.llptr) {
  1165.             futp = currp->next;
  1166.             /* must save a ptr to node to be processed next, futp, 
  1167.                                               because will 'delete' ptr to it now */
  1168.             delete(currp);
  1169.             currp = futp;
  1170.          }
  1171.          delete(currp);  /* don't forget last one in list */
  1172.       }
  1173.       else {
  1174.          delete(ptr->left);    /* delete left subtree */
  1175.          delete(ptr->u.right);   /* delete right subtree */
  1176.          free((char *)ptr);            /* unallocate memory location */
  1177.       }
  1178.    }
  1179.    return;
  1180. }
  1181.  
  1182. /*------------------------------------------------------*/
  1183. /*         F I N D _ A T T R        */
  1184. /* Searches through the attribute list for the  */
  1185. /* given name and returns the pointer to list   */
  1186. /* entry if found, else returns NULL.     */
  1187. /*------------------------------------------------------*/
  1188. ATTRDESC *find_attr(thisattr,thisadp)
  1189. char thisattr[];
  1190. ATTRDESC *thisadp;
  1191. {
  1192.    while((thisadp!=NULL) && (strcmp(thisattr,thisadp->attrname)!=0))
  1193.       thisadp = thisadp->next;
  1194.    return(thisadp);
  1195. }
  1196.  
  1197. /*------------------------------------------------------*/
  1198. /*       F I N D _ G R O U P        */
  1199. /* Searches through the group list for the   */
  1200. /* given name and returns the pointer to list   */
  1201. /* entry if found, else returns NULL.     */
  1202. /*------------------------------------------------------*/
  1203. GROUPDESC *find_group(thisgroup,thisgrp)
  1204. char thisgroup[];
  1205. GROUPDESC *thisgrp;
  1206. {
  1207.    while((thisgrp!=NULL) && (strcmp(thisgroup,thisgrp->groupname)!=0))
  1208.       thisgrp = thisgrp->next;
  1209.    return(thisgrp);
  1210. }
  1211.  
  1212. /*------------------------------------------------------*/
  1213. /*          F I N D _ I D        */
  1214. /* Searches through the ID list for the given   */
  1215. /* name and returns the pointer to the list  */
  1216. /* entry if the name is found, else returns NULL.  */
  1217. /*------------------------------------------------------*/
  1218. BOOLEAN find_id(idptr,thisname)
  1219. ID_IDREF_DESC *idptr;
  1220. char thisname[];
  1221. {
  1222.    while(idptr!=NULL && strcmp(idptr->name,thisname)!=0)
  1223.       idptr = idptr->next;
  1224.    return(idptr!=NULL ? TRUE : FALSE);
  1225. }
  1226.  
  1227. /*------------------------------------------------------*/
  1228. /*           F I N D _ E N T I T Y        */
  1229. /* Searches through the ENTITY list for the given  */
  1230. /* name and returns the pointer to the list  */
  1231. /* entry if the name is found, else returns NULL.  */
  1232. /* If there is a #DEFAULT entry and a direct       */
  1233. /* match is not found, the ptr to the first        */
  1234. /* #DEFAULT entry is returned.                     */
  1235. /*------------------------------------------------------*/
  1236. ENTITYDESC *find_entity(entptr,thisname,look_for_default)
  1237. ENTITYDESC *entptr;
  1238. char thisname[];
  1239. BOOLEAN look_for_default;
  1240. {
  1241.    ENTITYDESC *first_def;
  1242.  
  1243.    first_def = NULL;  /* points to first #DEFAULT entry in list */
  1244.    while(entptr!=NULL && strcmp(entptr->entityname,thisname)!=0) {
  1245.       if (first_def==NULL && look_for_default && strcmp(entptr->entityname,"#DEFAULT")==0)
  1246.          first_def = entptr;
  1247.       entptr = entptr->next;
  1248.    }
  1249.    return(entptr==NULL ? first_def : entptr);
  1250. }
  1251.  
  1252. /*------------------------------------------------------*/
  1253. /*                F I N D _ E X C E P T                 */
  1254. /* This routine searches the exception list  */
  1255. /* (inclusion or exclusion) for the identifier  */
  1256. /* specified in the parameter list.    */
  1257. /*------------------------------------------------------*/
  1258. BOOLEAN find_except(exptr,thisid)
  1259. EXCEPTDESC *exptr;
  1260. int thisid;
  1261. {
  1262.    while(exptr!=NULL && exptr->tokenid!=thisid)
  1263.       exptr = exptr->nextglobal;
  1264.    return(exptr!=NULL ? TRUE : FALSE);
  1265. }
  1266.  
  1267. /*------------------------------------------------------*/
  1268. /*          I N S E R T       */
  1269. /* This routine inserts IDs or IDREFs at the end   */
  1270. /* of their appropriate seperate singly linked  */
  1271. /* lists.  A flag is passed to indicate which   */
  1272. /* list the name is to be added to.  If the name   */
  1273. /* is already present in the list, an error is  */
  1274. /* raised.                 */
  1275. /*------------------------------------------------------*/
  1276. void insert(head,thisname,declvalcode)
  1277. ID_IDREF_DESC **head;
  1278. char thisname[];
  1279. DECLVAL declvalcode;
  1280. {
  1281.    ID_IDREF_DESC *thisptr,*prevptr;
  1282.  
  1283.    thisptr = *head;
  1284.    while(thisptr!=NULL && strcmp(thisptr->name,thisname)!=0) {
  1285.       prevptr = thisptr;
  1286.       thisptr = thisptr->next;
  1287.    }
  1288.    if (thisptr==NULL && strcmp(prevptr->name,thisname)!=0) {
  1289.       if (*head == NULL)
  1290.          thisptr = *head = id_idref_alloc();
  1291.       else 
  1292.           thisptr = prevptr->next = id_idref_alloc();
  1293.       strcpy(thisptr->name,thisname);
  1294.       thisptr->next = NULL;
  1295.    }
  1296.    else
  1297.       if (declvalcode == ID) {
  1298.          sprintf(error_msg,"%s%s%s","\nError: Duplicate ID attribute values of '",thisname,"'.\n");
  1299.          FATAL_ERROR()
  1300.       }
  1301.    return;
  1302. }
  1303.  
  1304. /*------------------------------------------------------*/
  1305. /*               L A S T _ S U B L I S T                */
  1306. /* This routine is used to find the end of the  */
  1307. /*      sub-exception list.  That is, the list of  */
  1308. /*      elements declared as an exception for that */
  1309. /*      particular generic identifier.       */
  1310. /*------------------------------------------------------*/
  1311. EXCEPTDESC *last_sublist(thisglob,thisloc)
  1312. EXCEPTDESC *thisglob,*thisloc;
  1313. {
  1314.    if (thisglob==NULL || thisloc==NULL)
  1315.       software_fault();
  1316.  
  1317.    while(thisglob->nextglobal!=thisloc && thisglob->nextglobal!=NULL)
  1318.       thisglob = thisglob->nextglobal;
  1319.    return(thisglob);
  1320. }
  1321.  
  1322. /*------------------------------------------------------*/
  1323. /*               L A S T _ G L O B A L                  */
  1324. /* This routine is used to find the end of the  */
  1325. /*      entire exception list.  That is, the current  */
  1326. /*      list of elements active as an exception.   */
  1327. /*------------------------------------------------------*/
  1328. EXCEPTDESC *last_global(ptr)
  1329. EXCEPTDESC *ptr;
  1330. {
  1331.    if (ptr != NULL)
  1332.       while(ptr->nextglobal != NULL)
  1333.          ptr = ptr->nextglobal;
  1334.    return(ptr);
  1335. }
  1336.  
  1337. /*------------------------------------------------------*/
  1338. /*                L O O K S T A C K            */
  1339. /*                   */
  1340. /*        Returns    :top value on the stack            */
  1341. /*                                               */
  1342. /*        Returns the top value of the stack          */
  1343. /*        but does not pop it off.                    */
  1344. /*------------------------------------------------------*/
  1345. STENTRY *lookstack()
  1346. {
  1347.    STENTRY *ptr;
  1348.    if ((ptr=pop()) != NULL)    /*  pop value  */
  1349.       push(ptr);      /*  push it back on the stack  */
  1350.    return(ptr);
  1351. }
  1352.  
  1353. /*------------------------------------------------------*/
  1354. /*                    N U L L F N C                     */
  1355. /* This routine doesn't do much of anything. */
  1356. /* It is called by function prototypes to get   */
  1357. /* around calling certain routines.  For example,  */
  1358. /* we don't want to call 'our_fputc' when the   */
  1359. /* outdoc is not to be built.       */
  1360. /*------------------------------------------------------*/
  1361. nullfnc(value)
  1362. int value;
  1363. {
  1364.    return(value);
  1365. }
  1366.  
  1367. /*------------------------------------------------------*/
  1368. /*                  O U R _ F G E T C                   */
  1369. /*      This routine is similiar to K&R's standard */
  1370. /*      fgetc.  However, It does first read from our  */
  1371. /*      input stack if something exists on it.     */
  1372. /*      Otherwise, it does it's own fgetc.      */
  1373. /*------------------------------------------------------*/
  1374. our_fgetc(ind)
  1375. FILE *ind;
  1376. {
  1377.    register int inchar,retval;
  1378.    INPUT_STACK *delptr;
  1379.  
  1380.    /*  We are allowing for future revisions that might require the input
  1381.        for the document element parser to come from more than one source.  */
  1382.  
  1383.    if (stptr == NULL) {
  1384.       while ((retval=((inchar=fgetc(indoc))==CTRLZ ? EOF:inchar)) == EOF && --fpindx>=0) {
  1385.          fclose(fpstack[fpindx+1]);
  1386.          indoc = fpstack[fpindx];
  1387.          entitylevel--;
  1388.       }
  1389.       putchar(retval);
  1390.    }
  1391.    else {
  1392.       retval = stptr->inchar;
  1393.       delptr = stptr;
  1394.       stptr = stptr->next;
  1395.       free((char *)delptr);
  1396.    }
  1397.    return(retval);
  1398. }
  1399.  
  1400. /*------------------------------------------------------*/
  1401. /*                O U R _ U N G E T C                   */
  1402. /*      This routine is similiar to K&R's standard */
  1403. /*      ungetc.  However, It creates and uses its     */
  1404. /*      input stack and places the ungot character    */
  1405. /*      on it.                                  */
  1406. /*------------------------------------------------------*/
  1407. void our_ungetc(c,indoc)
  1408. int c;
  1409. FILE *indoc;
  1410. {
  1411.    INPUT_STACK *newptr;
  1412.  
  1413.    newptr = isalloc();
  1414.    newptr->inchar = c;
  1415.    newptr->next = stptr;
  1416.    stptr = newptr;
  1417.    return;
  1418. }
  1419.  
  1420. /*------------------------------------------------------*/
  1421. /*              O U R _ T O U P P E R                   */
  1422. /*    We need toupper implemented as a function.        */
  1423. /*------------------------------------------------------*/
  1424. our_toupper(value)
  1425. int value;
  1426. {
  1427.    if (isascii(value) && isalpha(value) && islower(value))
  1428.       return(toupper(value) & 0xFF);
  1429.    return(value & 0xFF);
  1430. }
  1431.  
  1432. /*------------------------------------------------------*/
  1433. /*                P R O C E S S _ A T T R             */
  1434. /*     This routine is a pre-processor for exe_attr     */
  1435. /*     that reads from 'indoc' and resolves all    */
  1436. /*     references, possibly deleting leading and   */
  1437. /*     trailing spaces, then placing the resulting */
  1438. /*     string in 'buffer'.          */
  1439. /*------------------------------------------------------*/
  1440. process_attr(buffer,delim,genthead,dvcode,num_csdata)
  1441. char buffer[];
  1442. int delim;
  1443. ENTITYDESC *genthead;
  1444. DECLVAL dvcode;
  1445. unsigned *num_csdata;
  1446. {
  1447.    int inchar,indx,charnum,actual_length,inter_length;
  1448.    char entname[NAMELEN+1],number[NAMELEN+1];
  1449.    ENTITYDESC *entptr;
  1450.    BOOLEAN datatext_read;
  1451.  
  1452.    if (dvcode != ENUM_CDATA)
  1453.       actual_length = gettilnosep();
  1454.  
  1455.    datatext_read = FALSE;
  1456.    actual_length = indx = *num_csdata = 0;
  1457.  
  1458.    while((inchar=our_fgetc(indoc))!=delim || entitylevel>0)
  1459.       if (inchar==ERO && !datatext_read)
  1460.          if (isalpha(inchar=our_fgetc(indoc))) {
  1461.             our_ungetc(inchar,indoc);
  1462.             inter_length = get_entname(entname,nullfnc);
  1463.             if (entitylevel == 0)
  1464.                actual_length += inter_length+1;  /* includes the '&' */
  1465.  
  1466.             if ((entptr=find_entity(genthead,entname,TRUE)) == NULL) {
  1467.                sprintf(error_msg,"%s%s%s","\nError: Unknown general entity name '",entname,"'.\n");
  1468.                FATAL_ERROR()
  1469.             }
  1470.             else
  1471.                check_entity(dvcode==ENUM_CDATA,num_csdata,entptr,&datatext_read,entname,&actual_length,TRUE,&inchar);
  1472.          }
  1473.          else
  1474.             if (inchar == '#')
  1475.                if (isalpha(inchar=our_fgetc(indoc))) {
  1476.                   our_ungetc(inchar,indoc);
  1477.                   inter_length = get_entname(entname,our_toupper);
  1478.                   if (entitylevel == 0)
  1479.                      actual_length += inter_length+2;
  1480.                   if (strcmp(entname,"TAB") == 0)
  1481.                      buffer[indx++] = SEPCHAR;
  1482.                   else
  1483.                      if (strcmp(entname,"RS") == 0)
  1484.                         buffer[indx++] = RS;
  1485.                      else
  1486.                         if (strcmp(entname,"RE") == 0)
  1487.                            buffer[indx++] = RE;
  1488.                         else
  1489.                            if (strcmp(entname,"SPACE") == 0)
  1490.                               buffer[indx++] = SPACE;
  1491.                            else {
  1492.                               sprintf(error_msg,"%s%s%s","\nError: Unknown character reference '",entname,"'.\n");
  1493.                               FATAL_ERROR()
  1494.                            }
  1495.                   if ((inchar=our_fgetc(indoc)) != REFC)
  1496.                      our_ungetc(inchar,indoc);
  1497.                   else
  1498.                      actual_length++;
  1499.                }
  1500.                else
  1501.                   if (isdigit(inchar)) {
  1502.                      our_ungetc(inchar,indoc);
  1503.                      inter_length = get_number(number,nullfnc);
  1504.                      if (entitylevel == 0)
  1505.                         actual_length += inter_length+2;
  1506.                      CLEAR_BUF();  /* don't want number printed out */
  1507.  
  1508.                      charnum = atoi(number);
  1509.                      if ((charnum<CHARSET_LOWBOUND) || (charnum>CHARSET_HIGHBOUND))
  1510.                         ourexit(2,"\nError: Invalid character reference number\n");
  1511.                      else
  1512.                         buffer[indx++] = charnum;
  1513.                      if ((inchar=our_fgetc(indoc)) != REFC)
  1514.                         our_ungetc(inchar,indoc);
  1515.                      else
  1516.                         actual_length++;
  1517.                   }
  1518.                   else {
  1519.                      buffer[indx++] = ERO;
  1520.                      buffer[indx++] = '#';
  1521.                      buffer[indx++] = inchar;
  1522.                   }
  1523.             else {
  1524.                buffer[indx++] = ERO;
  1525.                buffer[indx++] = inchar;
  1526.             }
  1527.       else {
  1528.          if (entitylevel == 0)
  1529.             actual_length++;
  1530.          switch(inchar) {
  1531.          case RS:
  1532.             break;
  1533.          case OUR_EE:
  1534.             entitylevel--;
  1535.             datatext_read = FALSE;
  1536.             break;
  1537.          case RE:  
  1538.          case SEPCHAR:
  1539.             buffer[indx++] = SPACE;
  1540.             break;
  1541.          default:
  1542.             buffer[indx++] = inchar;
  1543.             break;
  1544.          }
  1545.       }
  1546.    our_ungetc(inchar,indoc);
  1547.    if (dvcode != ENUM_CDATA) {  /* will strip trailing seps from    */
  1548.                                 /* 'buffer' by decrementing 'indx'. */
  1549.       while(SEPERATOR(buffer[indx]))
  1550.          indx--;
  1551.       indx++;
  1552.    }
  1553.    buffer[indx] = '\0';
  1554.    return(actual_length);
  1555. }
  1556.  
  1557. /*------------------------------------------------------*/
  1558. /*                 T R Y _ E N T R E F                  */
  1559. /* This routine process general entity references, */
  1560. /* named character references, and numeric   char- */
  1561. /* acter references if they exist.        */
  1562. /*------------------------------------------------------*/
  1563. void try_entref(inchar,genthead,save_char,try_ft)
  1564. int inchar;
  1565. ENTITYDESC *genthead;
  1566. BOOLEAN save_char,*try_ft;
  1567. {
  1568.    register int charnum;
  1569.    ENTITYDESC *entptr;
  1570.    char entname[NAMELEN+1],
  1571.         number[NAMELEN+1],
  1572.         *outstr;
  1573.    static BOOLEAN datatext_read=FALSE;
  1574.  
  1575.    *try_ft = FALSE;
  1576.    outstr = get_char_mem(2);
  1577.    number[NAMELEN+1] = '\0';
  1578.    if (inchar==ERO && !datatext_read)
  1579.       /*  Found a general entity reference */
  1580.       if (isalpha(inchar=our_fgetc(indoc))) {
  1581.          our_ungetc(inchar,indoc);
  1582.          get_entname(entname,nullfnc);
  1583.          if ((entptr=find_entity(genthead,entname,TRUE)) == NULL) {
  1584.             sprintf(error_msg,"%s%s%s","\nError: Unknown general entity name '",entname,"'.\n");
  1585.             FATAL_ERROR()
  1586.          }
  1587.          else
  1588.             check_entity(TRUE,(unsigned int *) 0,entptr,&datatext_read,
  1589.                                             entname,(int *) 0,FALSE,&inchar);
  1590.       }
  1591.       else
  1592.          if (inchar == '#')
  1593.             /* Found a named character reference */
  1594.             if (isalpha(inchar=our_fgetc(indoc))) {
  1595.                our_ungetc(inchar,indoc);
  1596.                get_entname(entname,our_toupper);
  1597.                if (strcmp(entname,"TAB") == 0) {
  1598.                   (*put_ctr)(SEPCHAR,ctrfp);
  1599.                   *outstr = SEPCHAR;
  1600.                   (*applic)(DATA_STG,outstr,"");
  1601.                }
  1602.                else
  1603.                   if (strcmp(entname,"RS") == 0) {
  1604.                      (*put_ctr)(RS,ctrfp);
  1605.                      *outstr = RS;
  1606.                      (*applic)(DATA_STG,outstr,"");
  1607.                   }
  1608.                   else
  1609.                      if (strcmp(entname,"RE") == 0) {
  1610.                         (*put_ctr)(RE,ctrfp);
  1611.                         *outstr = RE;
  1612.                         (*applic)(DATA_STG,outstr,"");
  1613.                      }
  1614.                      else
  1615.                         if (strcmp(entname,"SPACE") == 0) {
  1616.                            (*put_ctr)(SPACE,ctrfp);
  1617.                            *outstr = SPACE;
  1618.                            (*applic)(DATA_STG,outstr,"");
  1619.                         }
  1620.                         else {
  1621.                            sprintf(error_msg,"%s%s%s","\nError: Invalid named character reference '",entname,"'.\n");
  1622.                            FATAL_ERROR()
  1623.                         }
  1624.  
  1625.                if ((inchar=our_fgetc(indoc)) != REFC)
  1626.                   if (inchar == RE)  /* RS and RE are insignificant */
  1627.                      inchar = our_fgetc(indoc);  /* get RS */
  1628.                   else
  1629.                      our_ungetc(inchar,indoc);
  1630.  
  1631.             }
  1632.             else
  1633.                /* Found a numeric character reference */
  1634.                if (isdigit(inchar)) {
  1635.                   our_ungetc(inchar,indoc);
  1636.                   get_number(number,nullfnc);
  1637.                   CLEAR_BUF();  /* don't want number printed out */
  1638.                   charnum = atoi(number);
  1639.                   if ((charnum<CHARSET_LOWBOUND) || (charnum>CHARSET_HIGHBOUND)) {
  1640.                      sprintf(error_msg,"%s%s%s","\nError: Invalid numeric character reference '",number,"'.\n");
  1641.                      FATAL_ERROR()
  1642.                   }
  1643.                   else
  1644.                      if (!SGMLCHAR(charnum)) {
  1645.                         (*print_ctr)(ctrfp,"\n[#%d]",charnum);
  1646.                         *try_ft = TRUE;
  1647.                      }
  1648.                      else
  1649.                         (*put_ctr)(charnum,ctrfp);
  1650.                   *outstr = charnum;
  1651.                   (*applic)(DATA_STG,outstr,"");
  1652.                   if ((inchar=our_fgetc(indoc)) != REFC) {
  1653.                      if (inchar == RE)  /* RS and RE are insignificant */
  1654.                         inchar = our_fgetc(indoc);  /* get RS */
  1655.                      else
  1656.                         our_ungetc(inchar,indoc);
  1657.                   }
  1658.                }
  1659.                else {
  1660.                   our_ungetc(inchar,indoc);
  1661.                   (*print_ctr)(ctrfp,"%c#",ERO);
  1662.                   *outstr = ERO;
  1663.                   (*applic)(DATA_STG,outstr,""); 
  1664.                   (*applic)(DATA_STG,"#","");
  1665.                }
  1666.          else {
  1667.             our_ungetc(inchar,indoc);
  1668.             (*print_ctr)(ctrfp,"%c",ERO);
  1669.             *outstr = ERO;
  1670.             (*applic)(DATA_STG,outstr,"");
  1671.          }
  1672.    else
  1673.       if (inchar == OUR_EE) {
  1674.          datatext_read = FALSE;
  1675.          entitylevel--;
  1676.       }
  1677.       else
  1678.          if (save_char)
  1679.             our_ungetc(inchar,indoc);
  1680.          else
  1681.             if (inchar != EOF) {
  1682.                (*put_ctr)(inchar,ctrfp);
  1683.                *outstr = inchar;
  1684.                (*applic)(DATA_STG,outstr,"");
  1685.             }
  1686.    free(outstr);
  1687.    return;
  1688. }
  1689.  
  1690. /*------------------------------------------------------*/
  1691. /*                R E S O L V E _ A T T R               */
  1692. /* This routine resolves the defaults that were */
  1693. /* not explicitly specified in the attribute */
  1694. /* specifications.  The defaults are outputted  */
  1695. /* to 'outdoc' and IDs and IDREFs are added to  */
  1696. /* their appropriate linked lists.        */
  1697. /*------------------------------------------------------*/
  1698. resolve_attr(headadp,print_to_file)
  1699. ATTRDESC *headadp;
  1700. int print_to_file;
  1701. {
  1702.    char outvalue[LITLEN+1];  /* allow for null terms */
  1703.    char buffer[NAMELEN+1];
  1704.    register int i,j;
  1705.    unsigned num_id_idref;
  1706.    BOOLEAN more_def_desc;
  1707.    ATTRDESC *thisadp;
  1708.  
  1709.    num_id_idref = 0;
  1710.    for (thisadp=headadp; thisadp!=NULL; thisadp=thisadp->next) {
  1711.       if (print_to_file == FALSE)
  1712.          putstr_outbuf("\n ");
  1713.       else
  1714.          (*print_ctr)(ctrfp,"\n ");
  1715.       if ((thisadp->defcode==A_IMPLIED||thisadp->defcode==A_CONREF) &&
  1716.           thisadp->processed==FALSE) {
  1717.          if (print_to_file == FALSE) {
  1718.             putchar_outbuf(' '); 
  1719.             putstr_outbuf(thisadp->attrname);
  1720.             putstr_outbuf("=#IMPLIED");
  1721.             place_in_queue(TAG_ATTR,thisadp->attrname,"");
  1722.          }
  1723.          else {
  1724.             if (thisadp->dvcode==ID||thisadp->dvcode==IDREF||thisadp->dvcode==IDREFS)
  1725.                num_id_idref++;
  1726.             (*print_ctr)(ctrfp," %s=#IMPLIED",thisadp->attrname);
  1727.             (*applic)(TAG_ATTR,thisadp->attrname,"");
  1728.          }
  1729.       }
  1730.       else {
  1731.          if (thisadp->dvcode==GROUP || thisadp->dvcode==NOTATION)
  1732.             strcpy(outvalue,thisadp->u2.currgrp->groupname);
  1733.          else        
  1734.              strcpy(outvalue,thisadp->u2.currdef);
  1735.          switch(thisadp->defcode) {
  1736.          case A_CURRENT:   /* if current and IDREF, already in list */
  1737.             if (thisadp->dvcode == ID) {
  1738.                sprintf(error_msg,"%s%s'.\n","\nError: ID values not unique after default resolution '",thisadp->attrname);
  1739.                FATAL_ERROR()
  1740.             }
  1741.             if (thisadp->dvcode==IDREF || thisadp->dvcode==IDREFS)
  1742.                num_id_idref++;
  1743.             break;
  1744.          case A_UNFIXED:  
  1745.          case A_FIXED:
  1746.          case A_REQD:     
  1747.          case A_IMPLIED: 
  1748.          case A_CONREF:
  1749.             if (thisadp->dvcode==ID || thisadp->dvcode==IDREF) {
  1750.                num_id_idref++;
  1751. #ifdef OLD
  1752.                memset(buffer,'\0',NAMELEN+1);
  1753. #else
  1754.                memset(buffer,'\0',sizeof(buffer));
  1755. #endif
  1756.                for (i=0; i<strlen(outvalue) && i<NAMELEN; i++)
  1757.                   buffer[i] = outvalue[i];
  1758. #ifdef OLD
  1759.                if (i >= NAMELEN)
  1760.                   ourexit(2,"\nError: ID-IDREF name violates NAMELEN quantity\n");
  1761. #else
  1762.                if (strlen(buffer) > NAMELEN)
  1763.                   ourexit(2,"\nError: ID-IDREF name violates NAMELEN quantity\n");
  1764. #endif
  1765.                if (thisadp->dvcode == ID)
  1766.                   insert(&idhead,buffer,thisadp->dvcode);
  1767.                else
  1768.                   insert(&idrefhead,buffer,thisadp->dvcode);
  1769.             }
  1770.             else
  1771.                if (thisadp->dvcode == IDREFS) {
  1772.                   more_def_desc = TRUE;
  1773.                   i = 0;
  1774.                   while(more_def_desc) {
  1775.                      num_id_idref++;
  1776.                      while(thisadp->u2.currdef[i] == ' ')
  1777.                         i++;
  1778.                      memset(buffer,'\0',NAMELEN+1);
  1779.                      j = 0;
  1780.                      while(!(SEPERATOR(thisadp->u2.currdef[i])) && thisadp->u2.currdef[i]!='\0') {
  1781.                         buffer[j] = thisadp->u2.currdef[i]; 
  1782.                         i++;  j++;
  1783.                      }
  1784.                      insert(&idrefhead,buffer,thisadp->dvcode);
  1785.                      more_def_desc = (thisadp->u2.currdef[i] != '\0');
  1786.                   }
  1787.                }
  1788.             break;
  1789.          }
  1790.          if (print_to_file == FALSE) {
  1791.             putchar_outbuf(' '); 
  1792.             putstr_outbuf(thisadp->attrname);    
  1793.             putstr_outbuf("=\"");
  1794.             output_with_lb(strlen(thisadp->attrname)+3,outvalue,FALSE);
  1795.             putstr_outbuf("\"");
  1796.             place_in_queue(TAG_ATTR,thisadp->attrname,outvalue);
  1797.          }
  1798.          else {
  1799.             if (thisadp->dvcode==ID||thisadp->dvcode==IDREF||thisadp->dvcode==IDREFS)
  1800.                num_id_idref++;
  1801.             (*print_ctr)(ctrfp," %s=\"",thisadp->attrname);
  1802.             output_with_lb(strlen(thisadp->attrname)+3,outvalue,TRUE);
  1803.             (*print_ctr)(ctrfp,"\"");
  1804.             (*applic)(TAG_ATTR,thisadp->attrname,outvalue);
  1805.          }
  1806.       }
  1807.    }
  1808.    return(num_id_idref);
  1809. }
  1810.  
  1811. /*--------------------------------------------------------------*/
  1812. /*             O U T P U T _ W I T H _ L B                      */
  1813. /* The CTR requires that output of data or attribute  */
  1814. /* values exceeding a column position (nominally 60)  */
  1815. /* be broken into multiple lines with a line-break    */
  1816. /* character placed at the end of each line.    */
  1817. /*--------------------------------------------------------------*/
  1818. void output_with_lb(currcol,outstr,print_to_file)
  1819. int currcol;
  1820. char *outstr;
  1821. BOOLEAN print_to_file;
  1822. {
  1823.    char *cptr,buffer[13];
  1824.  
  1825.    for (cptr=outstr; *cptr != '\0'; cptr++)
  1826.       if (++currcol > MAXCOL) {
  1827.          if (print_to_file)
  1828.             if (SGMLCHAR(*cptr))
  1829.                (*print_ctr)(ctrfp,"|\n%c",*cptr);
  1830.             else
  1831.                (*print_ctr)(ctrfp,"|\n[#%d]",*cptr);
  1832.          else {
  1833.             if (SGMLCHAR(*cptr)) {
  1834.                putstr_outbuf("|\n");
  1835.                putchar_outbuf(*cptr);
  1836.             }
  1837.             else {
  1838.                sprintf(buffer,"|\n[#%d]",*cptr);
  1839.                putstr_outbuf(buffer);
  1840.             }
  1841.          }
  1842.          currcol = 0;
  1843.       }
  1844.       else
  1845.          if (print_to_file)
  1846.             if (SGMLCHAR(*cptr))
  1847.                (*print_ctr)(ctrfp,"%c",*cptr);
  1848.             else
  1849.                (*print_ctr)(ctrfp,"\n[#%d]",*cptr);
  1850.          else
  1851.             if (SGMLCHAR(*cptr))
  1852.                putchar_outbuf(*cptr);
  1853.             else {
  1854.                sprintf(buffer,"\n[#%d]",*cptr);
  1855.                putstr_outbuf(buffer);
  1856.             }
  1857.    return;
  1858. }
  1859.  
  1860. /*------------------------------------------------------*/
  1861. /*       F I L L U P          */
  1862. /* Used to fill up the rest of name, nmtoken,   */
  1863. /* or nutoken array.  Input is taken from the   */
  1864. /* input document and the same restrictions  */
  1865. /* apply here in terms of NAMELEN.        */
  1866. /*------------------------------------------------------*/
  1867. void fillup(string,indx,capitalize)
  1868. char string[];
  1869. int *indx;
  1870. int (*capitalize)();
  1871. {
  1872.    int inchar;
  1873.    inchar = our_fgetc(indoc);
  1874.    while(NAMECHAR(inchar) && *indx<=NAMELEN) {
  1875.       string[*indx] = (*capitalize)(inchar);  /* case insensitive */
  1876.       putchar_outbuf(string[(*indx)++]);
  1877.       inchar = our_fgetc(indoc);
  1878.    }
  1879.    our_ungetc(inchar,indoc);
  1880.    return;
  1881. }
  1882.  
  1883. /*------------------------------------------------------*/
  1884. /*------------------------------------------------------*/
  1885. /*------------------------------------------------------*/
  1886. void fillup2(string,indx,capitalize)
  1887. char string[];
  1888. int *indx;
  1889. int (*capitalize)();
  1890. {
  1891.    int inchar;
  1892.    inchar = our_fgetc(indoc);
  1893.    while(NAMECHAR(inchar) && *indx<=NAMELEN) {
  1894.       string[*indx] = (*capitalize)(inchar);  /* case insensitive */
  1895.       (*indx)++;
  1896.       inchar = our_fgetc(indoc);
  1897.    }
  1898.    our_ungetc(inchar,indoc);
  1899.    return;
  1900. }
  1901.